package com.zzwtec.loader;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.catalina.loader.WebappClassLoader;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import com.zzwtec.bytecode.TimeClassVisitor;

/**
 * 自定义的TransformClassLoader 可以在加载的class中插入监控代码 
 * @author yangtonggan
 * @date 2016-9-20
 */
public class TransformClassLoader extends WebappClassLoader {
	/**
	 * 默认构造器
	 */
	public TransformClassLoader() {
		super();
		System.out.println("com.zzwtec.loader.TransformClassLoader被装载");
	}

	/**
	 * 默认构造器
	 * 
	 * @param parent
	 */
	public TransformClassLoader(ClassLoader parent) {
		super(parent);
		System.out.println("com.zzwtec.loader.TransformClassLoader被装载");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.apache.catalina.loader.WebappClassLoader#findClass(java.lang.String)
	 */
	public Class<?> findClass(String name) throws ClassNotFoundException {
		// 建议表达式读取属性文件
		String pattern = "^com.zzwtec.community.action.+Controller$";
		if (matchReg(name, pattern)) {
			return transformClass(name);
		} else {
			return super.findClass(name);
		}

	}

	private Class<?> transformClass(String name) throws ClassNotFoundException {
		FileInputStream in = null;
		try {
			StringBuilder sb = new StringBuilder();
			sb.append(getResources().getNameInNamespace());
			sb.append("/WEB-INF/classes/");
			String basePath = sb.toString();
			String className = basePath + name.replace('.', '/') + ".class";
			in = new FileInputStream(className);
			ByteArrayOutputStream buffer = new ByteArrayOutputStream();
			int len = -1;
			byte[] buf = new byte[1024];
			while ((len = in.read(buf)) != -1) {
				buffer.write(buf, 0, len);
			}
			// 读取类的字节码流
			ClassReader reader = new ClassReader(buffer.toByteArray());
			// 创建操作字节流值对象，ClassWriter.COMPUTE_MAXS:表示自动计算栈大小
			ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS);
			// 接受一个ClassVisitor子类进行字节码修改
			TimeClassVisitor tcv = new TimeClassVisitor(writer, name);
			tcv.visitAnnotation("Lcom/zzwtec/bytecode/ExclusiveTime;", true);
			reader.accept(tcv, 8);
			// 返回修改后的字节码流
			byte[] buf2 = writer.toByteArray();
			Class<?> cl = defineClass(name, buf2, 0, buf2.length);
			if (cl == null) {
				cl = super.findClass(name);
			}
			return cl;
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			close(in);
		}

	}

	/**
	 * 关闭输入流
	 * 
	 * @param in
	 */
	private void close(InputStream in) {
		try {
			if (in != null) {
				in.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 如果匹配正则，
	 * 
	 * @param str
	 * @param patt ^com.zzwtec.community.action.+Controller$
	 * @return
	 */
	private boolean matchReg(String str, String patt) {
		try {
			String pattern = patt;
			Pattern r = Pattern.compile(pattern);
			Matcher m = r.matcher(str);
			return m.matches();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

}
